package com.mysoft.gfyx.marketdevelop.service.impl;

import com.mysoft.framework.cache.api.CacheProvider;
import com.mysoft.framework.common.exception.BusinessLogicException;
import com.mysoft.framework.common.util.MappingUtil;
import com.mysoft.framework.modeling.dto.*;
import com.mysoft.gfyx.common.concurrency.CacheAgentService;
import com.mysoft.gfyx.common.concurrency.impl.CacheAgentServiceImpl;
import com.mysoft.gfyx.common.concurrency.CacheLockService;
import com.mysoft.gfyx.common.time.TimeService;
import com.mysoft.gfyx.marketdevelop.controller.dto.inspect.ChartRequestDto;
import com.mysoft.gfyx.marketdevelop.controller.dto.inspect.MultiPieResponseDto;
import com.mysoft.gfyx.marketdevelop.controller.dto.inspect.PieResponseDto;
import com.mysoft.gfyx.marketdevelop.mip.GetDeveloperDataService;
import com.mysoft.gfyx.marketdevelop.mip.dto.*;
import com.mysoft.gfyx.marketdevelop.mip.dto.TjCustom.GetTakenLandTop10RequestDto;
import com.mysoft.gfyx.marketdevelop.mip.dto.TjCustom.SqlApiListResponseDto;
import com.mysoft.gfyx.marketdevelop.mip.dto.TjCustom.SqlApiResponseDto;
import com.mysoft.gfyx.marketdevelop.mip.dto.TjCustom.TakenLandBarRequestDto;
import com.mysoft.gfyx.marketdevelop.mip.dto.TjMetric.*;
import com.mysoft.gfyx.marketdevelop.service.*;
import com.mysoft.gfyx.marketdevelop.service.dto.metric.IndicatorDto;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Service
public class InspectTakeLandServiceImp extends BaseDataApiServiceImp implements InspectTakeLandService {
    @Autowired
    private DeveloperService developerService;

    @Autowired
    private GetDeveloperDataService getDeveloperDataService;

    @Autowired
    private LoadDataApiCommonService loadDataApiCommonService;

    @Autowired
    private LabelService labelService;

    @Autowired
    private MetricService metricService;

    @Autowired
    private TimeService timeService;

    @Autowired
    private CacheLockService cacheLockService;

    @Autowired
    private CacheAgentService cacheAgentService;

    @Autowired
    private CacheProvider cacheProvider;

    @Value("${tjdata.metrics.takeland}")
    private String metricTakeLand;

    public FieldsSetting loadFields() {
        //硬编码的获取字段逻辑
        FieldsSetting fieldsSetting = new FieldsSetting();
        fieldsSetting.setIdField("uuid");
        fieldsSetting.setFields(new ArrayList<>());
        String groupName = "inspect_take_land";
        fieldsSetting.getFields().add(new DataApiField("uuid", groupName, "RowID", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("id", groupName, "拿地ID", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("developer_name", groupName, "拿地企业", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("organizing_code", groupName, "社会统一信用代码", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("company_type_label", groupName, "拿地企业类型", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("top_developer_name", groupName, "顶级企业", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("top_organizing_code", groupName, "社会统一信用代码", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("top_company_type_label", groupName, "顶级公司类型", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("info_type", groupName, "信息类型", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("trade_type", groupName, "成交类型", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("take_land_price", groupName, "成交价格（万元）", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("take_land_date", groupName, "拿地日期", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("build_start_plan", groupName, "约定开工时间", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("build_end_plan", groupName, "约定竣工时间", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("land_usage_category", groupName, "土地类型分类", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("land_usage", groupName, "土地类型", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("land_usage_label", groupName, "土地类型标签", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("all_area", groupName, "总面积(平米)", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("planned_area", groupName, "规划总建面积(平米)", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("province", groupName, "区域（省）", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("province_code", groupName, "区域（省）Code", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("city", groupName, "区域（市）", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("city_code", groupName, "区域（市）Code", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("land_address", groupName, "地址", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("land_title", groupName, "土地名称", FieldType.String));
        fieldsSetting.getFields().add(new DataApiField("is_price_gt_avg", groupName, "高端项目标签", FieldType.String));
        // 返回
        return fieldsSetting;
    }

    public ListDataResult loadData(LoadDataParams options) {
        Object provinceCode = options.getOptions().getContext().get("province_code");
        Object cityCode = options.getOptions().getContext().get("city_code");
        Object timeBegin = options.getOptions().getContext().get("time_begin");
        Object timeEnd = options.getOptions().getContext().get("time_end");


        ArrayList<String> tagsId = labelService.getTags(DeveloperService.TjEntity.TakingLand, new ArrayList<String>() {{
            add(LabelService.LABEL_COMPANY_TYPE);
            add(LabelService.LABEL_TOP_COMPANY_TYPE);
//            add(LabelService.LABEL_LAND_TYPE);
        }});

        GetDeveloperFilterDataRequestDto dto = new GetDeveloperFilterDataRequestDto();
        dto = developerService.setCommonData(dto, DeveloperService.TjEntity.TakingLand);
        dto.setTable_name(DeveloperService.TABLE_TAKE_LAND);
        dto.setPage(options.getPageIndex() + 1);
        dto.setPage_size(options.getPageSize());
        dto.setTag_ids(tagsId);

        if (provinceCode != null)
            dto.addFilterDtos("province_code", BaseTjFilterDto.OPERATE_EQUAL, provinceCode.toString(), DeveloperService.TABLE_TAKE_LAND, BaseTjFilterDto.ASSOCIATE_NONE);
        if (cityCode != null)
            dto.addFilterDtos("city_code", BaseTjFilterDto.OPERATE_EQUAL, cityCode.toString(), DeveloperService.TABLE_TAKE_LAND, BaseTjFilterDto.ASSOCIATE_AND);
        if (timeBegin != null)
            dto.addFilterDtos("take_land_date", BaseTjFilterDto.OPERATE_LARGER_EQUAL, timeBegin.toString(), DeveloperService.TABLE_TAKE_LAND, BaseTjFilterDto.ASSOCIATE_AND);
        if (timeEnd != null)
            dto.addFilterDtos("take_land_date", BaseTjFilterDto.OPERATE_LESS, timeEnd.toString(), DeveloperService.TABLE_TAKE_LAND, BaseTjFilterDto.ASSOCIATE_AND);

        List<Filter> filters = options.getOptions().getFilters();
        // 设计土地类型标签
        filters = labelService.setLandUsageLabel(filters, "land_usage");
        dto.addFilterByLoadDataApi(filters, DeveloperService.TABLE_TAKE_LAND, new HashMap<String, String>() {{
            put("company_type_label", DeveloperService.TABLE_LABEL);
            put("land_usage", DeveloperService.TABLE_TAKE_LAND_USAGE);
        }});

        ArrayList<GetDeveloperSortDto> sorts = new ArrayList<>();
        GetDeveloperSortDto sort = new GetDeveloperSortDto();
        sort.setSort_type(GetDeveloperSortDto.SORT_DESC);
        sort.setAttribute_name("take_land_date");
        sort.setTable_name(DeveloperService.TABLE_TAKE_LAND);
        sorts.add(sort);
        dto.setSorts(sorts);

        BaseTjListResponseDto res = getDeveloperDataService.getDeveloperMainAndDetailData(dto);

        return developerService.getTjResFromLoadData(res, getFilterChanger());
    }

    private class FilterChanger implements TjResultMapChangerService {
        @Override
        public void change(BaseTjListItemDto item) {
            if (item.getTag_infos() != null) {
                String companyType = labelService.extractAndDeleteTagValueNameWithTagName(item.getTag_infos(), DeveloperService.TjEntity.TakingLand, LabelService.LABEL_COMPANY_TYPE);
                String topCompanyType = labelService.extractAndDeleteTagValueNameWithTagName(item.getTag_infos(), DeveloperService.TjEntity.TakingLand, LabelService.LABEL_TOP_COMPANY_TYPE);
                String landUsageType = labelService.extractAndDeleteTagValueNameWithTagName(item.getTag_infos(), DeveloperService.TjEntity.TakingLand, LabelService.LABEL_LAND_TYPE);

                if (companyType != "") item.getItem().put("company_type_label", companyType);
                if (topCompanyType != "") item.getItem().put("top_company_type_label", topCompanyType);
                if (landUsageType != "") item.getItem().put("land_usage_label", landUsageType);

                String td = timeService.convertTimeFormat(item.getItem().getOrDefault("take_land_date", "").toString(), "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd");
                item.getItem().put("take_land_date", td);
                String bsp = timeService.convertTimeFormat(item.getItem().getOrDefault("build_start_plan", "").toString(), "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd");
                item.getItem().put("build_start_plan", bsp);
                String bep = timeService.convertTimeFormat(item.getItem().getOrDefault("build_end_plan", "").toString(), "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd");
                item.getItem().put("build_end_plan", bep);

                if (item.getItem().get("city").equals(item.getItem().get("province"))) item.getItem().put("city", "");
            }

        }
    }

    TjResultMapChangerService getFilterChanger() {
        return new InspectTakeLandServiceImp.FilterChanger();
    }

    public PieResponseDto takenLandUsagePie(ChartRequestDto dto) {

        String cacheKey = "TAKEN_LAND_USAGE_PIE:" + DigestUtils.md5Hex(dto.toString());
        PieResponseDto pieResponseDto = cacheAgentService.getCachedData(cacheKey);

        if (pieResponseDto != null) {
            return pieResponseDto;
        }

        pieResponseDto = new PieResponseDto();

        List<IndicatorDto> metrics = metricService.getMetricList(metricTakeLand);

        QueryMetricRequestDto queryMetricRequestDto = new QueryMetricRequestDto();
        developerService.setCommonData(queryMetricRequestDto);
        queryMetricRequestDto.setChart_type(QueryMetricRequestDto.CHART_DIM);
        metrics.forEach(m -> {
            QueryMetricIndicatorRequestDto queryMetricIndicatorRequestDto = MappingUtil.getSimpleMapperFacade().map(m, QueryMetricIndicatorRequestDto.class);
            queryMetricRequestDto.addIndicator(queryMetricIndicatorRequestDto);
        });

        QueryMetricConditionRequestDto calculate_condition = new QueryMetricConditionRequestDto();
        calculate_condition.addWhere(DeveloperService.TABLE_TAKE_LAND, "province_code", QueryMetricConditionWhereConditionRequestDto.OPERATE_EQ, dto.getProvince_code(), QueryMetricConditionWhereConditionRequestDto.VAL_TYPE_STR);
        if (dto.getCity_code() != null)
            calculate_condition.addWhere(DeveloperService.TABLE_TAKE_LAND, "city_code", QueryMetricConditionWhereConditionRequestDto.OPERATE_EQ, dto.getCity_code(), QueryMetricConditionWhereConditionRequestDto.VAL_TYPE_STR);
        calculate_condition.addWhere(DeveloperService.TABLE_TAKE_LAND, "take_land_date", QueryMetricConditionWhereConditionRequestDto.OPERATE_LARGER_EQ, dto.getTime_begin(), QueryMetricConditionWhereConditionRequestDto.VAL_TYPE_DATE);
        calculate_condition.addWhere(DeveloperService.TABLE_TAKE_LAND, "take_land_date", QueryMetricConditionWhereConditionRequestDto.OPERATE_LESS, dto.getTime_end(), QueryMetricConditionWhereConditionRequestDto.VAL_TYPE_DATE);

        calculate_condition.addGroup("land_usage_label", DeveloperService.TABLE_LABEL);
        //calculate_condition.addOrder(QueryMetricConditionOrderRequestDto.ORDER_DESC);

        queryMetricRequestDto.setCalculate_condition(calculate_condition);

        QueryMetricResponseDto res = getDeveloperDataService.queryMetric(queryMetricRequestDto);
        pieResponseDto.loadData(res);

        cacheAgentService.setCacheData(cacheKey, pieResponseDto);

        return pieResponseDto;
    }

    public MultiPieResponseDto takeLandUsagePieByApi(ChartRequestDto dto) {
        String cacheKey = "TAKEN_LAND_USAGE_PIE:" + DigestUtils.md5Hex(dto.toString());
        MultiPieResponseDto piesResponseDto = cacheAgentService.getCachedData(cacheKey);

        if (piesResponseDto != null) {
            return piesResponseDto;
        }

        SqlApiResponseDto sqlApiResponseDto = getDeveloperDataService.getLandPie(dto);

        piesResponseDto = new MultiPieResponseDto();
        piesResponseDto.loadData(sqlApiResponseDto, "land_usage", new String[]{"number", "all_area"});

        cacheAgentService.setCacheData(cacheKey, piesResponseDto);

        return piesResponseDto;
    }

    public Object takenLandRank(ChartRequestDto dto) {
        String cacheKey = "TAKEN_LAND_RANK:" + DigestUtils.md5Hex(dto.toString());
        Object rows = cacheAgentService.getCachedData(cacheKey);

        if (rows != null) {
            return rows;
        }

        GetTakenLandTop10RequestDto getTakenLandTop10RequestDto = MappingUtil.getSimpleMapperFacade().map(dto, GetTakenLandTop10RequestDto.class);

        SqlApiResponseDto res = getDeveloperDataService.getTakenLandTop10(getTakenLandTop10RequestDto);

        if (res.getData() == null) {
            throw new BusinessLogicException("找不到数据");
        }

        rows = res.getData().getRows();

        cacheAgentService.setCacheData(cacheKey, rows);
        return rows;
    }

    public Object takenLandUsageBar(ChartRequestDto dto) {
        String cacheKey = "TAKEN_LAND_BAR:" + DigestUtils.md5Hex(dto.toString());
        HashMap<String, Object> newRes = cacheAgentService.getCachedData(cacheKey);

        if (newRes != null) {
            return newRes;
        }

        TakenLandBarRequestDto takenLandBarRequestDto = MappingUtil.getSimpleMapperFacade().map(dto, TakenLandBarRequestDto.class);

        SqlApiListResponseDto res = getDeveloperDataService.getTakenLandBar(takenLandBarRequestDto);

        if (res.getData() == null) {
            throw new BusinessLogicException("找不到数据");
        }
        //数据转换
        ArrayList<Map<String, Object>> tagList = new ArrayList<>();
        HashMap<String, Integer> tagMap = new HashMap<>();
        AtomicReference<Integer> index = new AtomicReference<>(0);
        res.getData().forEach(item -> {
            if (item.get("tag_value_name") != null) {
                String name = item.get("tag_value_name").toString();
                int currentIndex;
                if (!tagMap.containsKey(name)) {
                    tagMap.put(name, index.get());
                    Map<String, Object> mData = new HashMap<>();
                    mData.put("name", name);
                    mData.put("data", new ArrayList<>());
                    tagList.add(mData);
                    currentIndex = index.get();
                    index.set(index.get() + 1);
                } else {
                    currentIndex = tagMap.get(name);
                }

                HashMap<String, Object> newItem = new HashMap<>();
                newItem.put("time", item.get("m"));
                newItem.put("value", item.get("num"));
                ((ArrayList) (tagList.get(currentIndex).get("data"))).add(newItem);
            }
        });

        newRes = new HashMap<>();
        newRes.put("pulsar_time", res.getData().size() > 0 ? res.getData().get(0).get("pulsar_time") : "");
        newRes.put("list", tagList);

        cacheAgentService.setCacheData(cacheKey, newRes);
        return newRes;
    }

}
